package com.leju.common.jsonparsing;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.text.TextUtils;

/**
 * @author 刘伟 E-mail: liuwei1@leju.com
 * @version 创建时间： 2013-4-19 上午10:39:08
 * @类说明： 通用json解析工具
 */

public class JsonParseTemplate {
	private static JsonParseTemplate instance = null;

	private JsonParseTemplate() {

	}

	public static JsonParseTemplate getInstance() {
		if (instance == null) {
			instance = new JsonParseTemplate();
		}
		return instance;
	}

	/**
	 * 解析一个JSONObject
	 * 
	 * @param clz
	 * @param object
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T getBean(Class<?> clz, JSONObject object) {
		if (object == null) {
			return null;
		}

		T bean;
		try {
			bean = ((T) clz.newInstance());
			if (bean != null) {
				if (checkIsUseAnnotation(clz)) {
					parseByAnnotation(bean, object);
				} else {
					parseByFiles(bean, object);
				}
			}
			return bean;
		} catch (Exception e) {

			e.printStackTrace();
		}

		return null;
	}

	/**
	 * 把一个jsonobject解析为一个指定的bean对象
	 * 
	 * @param clz
	 *            bean对象的class
	 * @param object
	 *            需要解析的JSONObject
	 * @param reflectMap
	 *            替换数组，里面存放的是需要替换的filed.getName(),比如bean里面有个属性是name
	 *            可是jsonobject里对应的节点名字是nameStr， 就需要一个Map map
	 *            map.put("name","nameStr");
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T getBean(Class<?> clz, JSONObject object,
			Map<String, String> reflectMap) {
		if (object == null) {
			return null;
		}
		T bean = null;
		if (reflectMap != null) {

			try {
				bean = (T) clz.newInstance();
			} catch (Exception e1) {
				throw new IllegalArgumentException(e1.toString());

			}
			Field[] files = clz.getFields();
			for (Field field : files) {
				if (fieldsFilter(field)) {
					try {

						String fieldName = field.getName();
						String nodeName = reflectMap.get(fieldName);
						nodeName = TextUtils.isEmpty(nodeName) ? fieldName
								: nodeName;

						setFieldValue(bean, field, object.getString(nodeName));
					} catch (Exception e) {

						e.printStackTrace();
					}
				}
			}
			return bean;

		} else {
			return getBean(clz, object);
		}

	}

	private <T> void parseByFiles(T bean, JSONObject object) {
		Field[] files = bean.getClass().getFields();
		for (Field field : files) {
			if (fieldsFilter(field)) {
				try {
					// field.set(bean, object.get(field.getName()));

					setFieldValue(bean, field,
							object.getString(field.getName()));
				} catch (Exception e) {

					e.printStackTrace();
				}
			}
		}

	}

	@SuppressWarnings("unused")
	private <T> void setFieldValue(T t, Field field, String value)
			throws Exception {
		if (field.getType() == int.class) {
			field.setInt(t, Integer.parseInt(value));
		} else if (field.getType() == long.class) {
			field.setLong(t, Long.parseLong(value));
		} else if (field.getType() == float.class) {
			field.setFloat(t, Float.parseFloat(value));
		} else if (field.getType() == double.class) {
			field.setDouble(t, Double.parseDouble(value));
		} else if (field.getType() == short.class) {
			field.setShort(t, Short.parseShort(value));
		} else if (field.getType() == byte.class) {
			field.setByte(t, Byte.parseByte(value));
		} else if (field.getType() == boolean.class) {
			field.setBoolean(t, Boolean.parseBoolean(value));
		} else {
			field.set(t, value);
		}

	}

	private <T> void parseByAnnotation(T bean, JSONObject object) {

		Class<?> cla = bean.getClass();
		JsonParsingAnnotation annotation = cla
				.getAnnotation(JsonParsingAnnotation.class);
		String[] beanFields = annotation.beanFileds();
		String[] jsonFields = annotation.jsonFileds();
		for (int i = 0; i < jsonFields.length; i++) {
			try {
				Field field = cla.getField(beanFields[i]);
				if (fieldsFilter(field)) {
					field.setAccessible(true);
					setFieldValue(bean, field, object.getString(jsonFields[i]));
				}

				// field.set(bean, object.get(jsonFields[i]));
			} catch (Exception e) {

				e.printStackTrace();
			}
		}

	}

	/**
	 * 从JsonArray里解析bean列表
	 * 
	 * @param jsonArray
	 * @return
	 */
	public <T> ArrayList<T> getBeans(Class<?> cla, JSONArray jsonArray) {
		if (jsonArray == null) {
		return null;
		}
		int arrayLength = jsonArray.length();
		ArrayList<T> list = new ArrayList<T>(arrayLength);
		for (int i = 0; i < arrayLength; i++) {
			try {
				JSONObject object = jsonArray.getJSONObject(i);
				T bean = getBean(cla, object);
				if (bean != null) {
					list.add(bean);
				}

			} catch (JSONException e) {

				e.printStackTrace();
			}
		}

		return list;
	}

	/**
	 * 从JsonArray里解析bean列表
	 * 
	 * @param cla
	 *            bean的class
	 * @param jsonArray
	 * @param relectMap
	 *            替换数组，里面存放的是需要替换的filed.getName(),比如bean里面有个属性是name
	 *            可是jsonobject里对应的节点名字是nameStr， 就需要一个Map map
	 *            map.put("name","nameStr");
	 * @return
	 */
	public <T> ArrayList<T> getBeans(Class<?> cla, JSONArray jsonArray,
			Map<String, String> relectMap) {
		if (jsonArray == null) {
			return null;
		}
		int arrayLength = jsonArray.length();
		ArrayList<T> list = new ArrayList<T>(arrayLength);
		if (relectMap == null) {
			for (int i = 0; i < arrayLength; i++) {
				try {
					JSONObject object = jsonArray.getJSONObject(i);
					T bean = getBean(cla, object);
					if (bean != null) {
						list.add(bean);
					}

				} catch (JSONException e) {

					e.printStackTrace();
				}
			}
		} else {
			for (int i = 0; i < arrayLength; i++) {
				try {
					JSONObject object = jsonArray.getJSONObject(i);
					T bean = getBean(cla, object, relectMap);
					if (bean != null) {
						list.add(bean);
					}

				} catch (JSONException e) {

					e.printStackTrace();
				}
			}
		}

		return list;
	}

	/**
	 * 从jsonarray中获取字符串数组
	 * 
	 * @param jsonArray
	 * @return
	 */
	public List<String> getStringList(JSONArray jsonArray) {
		ArrayList<String> arrayList = new ArrayList<String>();
		for (int i = 0; i < jsonArray.length(); i++) {
			try {
				arrayList.add(jsonArray.getString(i));
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return arrayList;
	}

	/**
	 * 判断属性是否和法，如果是static或者final的 返回false 表示不和法 ，过滤掉
	 * 
	 * @param field
	 * @return
	 */
	private boolean fieldsFilter(Field field) {
		boolean result = false;
		if (field == null) {
			result = false;
			return result;
		}

		if (Modifier.isStatic(field.getModifiers())
				|| Modifier.isFinal(field.getModifiers())) {
			return false;
		}
		Type type = field.getType();
		// if (!type.getClass().isPrimitive() && type != String.class) {
		// return false;
		// }
		Type[] types = { String.class, int.class, long.class, float.class,
				double.class, byte.class, short.class, char.class,
				boolean.class };
		for (int i = 0; i < types.length; i++) {
			if (type == types[i]) {
				return true;
			}
		}

		return result;

	}

	/**
	 * 判断目标bean是否添加了JsonParsingAnnotation注解
	 * 
	 * @return
	 */
	private boolean checkIsUseAnnotation(Class<?> cla) {

		JsonParsingAnnotation annotation = (JsonParsingAnnotation) cla
				.getAnnotation(JsonParsingAnnotation.class);
		if (annotation != null) {
			return true;
		}
		return false;
	}

}
